//
// Created by haoy on 2017/6/29.
//

#ifndef MERGE_LAYOUT_HPP
#define MERGE_LAYOUT_HPP

#include <cassert>
#include <list>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include "block.hpp"
#include "dimension.hpp"
#include "file.hpp"
#include "track.hpp"

class layout {
protected:
    layout() {}
public:
    virtual ~layout() {}
public:
    bool has_video() {
        return !video_tracks_.empty();
    }

    bool has_audio() {
        return !audio_tracks_.empty();
    }

    /* video_output_options get video layout filter */
    void video_output_options(std::vector<std::string>& options) {
        if(!has_video()) {
            options.emplace_back("-vn");
            return;
        }
        options.emplace_back("-filter_complex");
        options.emplace_back(_video_filter());
        return;
    }

    void audio_output_options(std::vector<std::string>& options) {
        if (!has_audio()) {
            options.emplace_back("-an");
            return;
        }
        auto bts = _begin_ts();
        std::ostringstream w;
        std::ostringstream w2;
        int source_id = -1;
        for (auto& a : audio_tracks_) {
            source_id++;
            auto abeg = a.begin_ts - bts;
            auto aend = _duration() - (abeg + a.duration_ms);
            std::ostringstream w3; w3 << 0;
            for (int i = 1; i < a.channel_nb; ++i) {
                w3 << "|" << 0;
            }
            w << "aevalsrc=" << w3.str() << ":d=" << abeg / 1000 << "." << abeg % 1000 << "[a" << source_id << "b];";
            w << a.filter << "[a" << source_id << "m];";
            w << "aevalsrc=" << w3.str() << ":d=" << aend / 1000 << "." << aend % 1000 << "[a" << source_id << "e];";
            w << "[a" << source_id << "b][a" << source_id << "m][a" << source_id << "e]";
            w << "concat=n=3:v=0:a=1,afifo[a" << source_id << "];";
            w2 << "[a" << source_id << "]";
        }
        w << w2.str();
        if (audio_tracks_.size() == 2 && audio_tracks_[0].channel_nb == audio_tracks_[1].channel_nb) {
            //ljh 20200526
            // auto& a0 = audio_tracks_[0];
            // auto& a1 = audio_tracks_[1];
            // std::ostringstream w4; w4 << "c0<c0";
            // for (int i = 1; i < a0.channel_nb; i += 2) {
            //     w4 << "+c" << i;
            // }
            // std::ostringstream w5; w5 << "c1<c" << a0.channel_nb;
            // for (int i = a0.channel_nb + 1; i < a0.channel_nb + a1.channel_nb; i += 2) {
            //     w5 << "+c" << i;
            // }
            // w << "amerge,pan=stereo|" << w4.str() << "|" << w5.str() << ",dynaudnorm=n=0:g=15:r=1.0";
            w << "amerge" << ",dynaudnorm=n=0:g=15:r=1.0";
        } else {
            w << "amix=inputs=" << audio_tracks_.size();
            // uncomment to boost audio volume
            //w << ":dropout_transition=0,dynaudnorm";
        }
        options.emplace_back("-filter_complex");
        options.emplace_back(w.str());
        return;
    }

    void add_video(video_filter_track& v) {
        video_tracks_.emplace_back(v);
    }

    void add_audio(audio_filter_track& a) {
        audio_tracks_.emplace_back(a);
    }

protected:
    uint64_t _begin_ts() {
        uint64_t begin_ts = -1;
        for (auto& v : video_tracks_) {
            if (v.begin_ts < begin_ts) {
                begin_ts = v.begin_ts;
            }
        }
        for (auto& a : audio_tracks_) {
            if (a.begin_ts < begin_ts) {
                begin_ts = a.begin_ts;
            }
        }
        return begin_ts;
    }

    uint64_t _duration() {
        uint64_t end_ts = 0;
        for (auto& v : video_tracks_) {
            if (v.begin_ts + v.duration_ms > end_ts) {
                end_ts = v.begin_ts + v.duration_ms;
            }
        }
        for (auto& a : audio_tracks_) {
            if (a.begin_ts + a.duration_ms > end_ts) {
                end_ts = a.begin_ts + a.duration_ms;
            }
        }
        return end_ts - _begin_ts();
    }

    std::vector<video_filter_track> video_tracks_;
    std::vector<audio_filter_track> audio_tracks_;
private:
    virtual std::string _video_filter() = 0;
};


#endif //MERGE_LAYOUT_HPP
